package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	_ "io"
	"os"
	"strconv"
	"time"

	"sorter/bubblesort"
	"sorter/qsort"
	"sorter/selectsort"
)

var (
	algorithmRegister map[string]func([]int) = map[string]func([]int){
		"qsort": func(values []int) {
			qsort.QuickSort(values)
		},
		"bubblesort": func(values []int) {
			bubblesort.BubbleSort(values)
		},
		"selectsort": func(values []int) {
			selectsort.SelectSort(values)
		},
	}
)

var inputFile *string = flag.String("i", "in.data", "InputFile contains values for sorting.")
var outputFile *string = flag.String("o", "out.data", "OutputFile receive sorting values.")
var algorithm *string = flag.String("a", "bubblesort", "Values sort algorithm optional value [bubblesort, qsort].")

func main() {
	flag.Parse()
	if inputFile != nil {
		fmt.Println("inputFile = ", *inputFile, " outputFile = ", *outputFile, " algorithm = ", *algorithm)
	}
	values, err := readValuesFromFile(*inputFile)
	if err == nil {
		if sorter, ok := algorithmRegister[*algorithm]; ok {
			fmt.Printf("Sort Before :\n%v\n", values)
			start := time.Now()
			sorter(values)
			end := time.Now()
			fmt.Printf("Sort After :\n%v\n", values)
			fmt.Printf("Sort cost time %v naos .\n", end.Sub(start).Nanoseconds())
		} else {
			fmt.Println("Not algorithm or Not support algorithm ", *algorithm)
		}
		err = writeValuesToFile(values, *outputFile)
		if err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Println(err)
	}
}

func writeValuesToFile(values []int, outputFile string) (err error) {
	file, err := os.Create(outputFile)
	if err != nil {
		return errors.New(err.Error() + " Create file " + outputFile + " failed.")
	}
	defer file.Close()
	for _, value := range values {
		sline := strconv.Itoa(value)
		file.WriteString(sline + "\n")
	}
	return nil
}

/*
values是Slice类型，因为Array在Go中是值拷贝
而在排序中则需要对固定地址的元素进行修改排序
可以采用数组指针实现，不过这里采用Go提供的Slice类型实现
*/
func readValuesFromFile(inputFile string) ([]int, error) {
	var file, err = os.Open(inputFile)
	if err != nil {
		return nil, errors.New(err.Error() + " Open inputFile " + inputFile + " failed.")
	}
	defer file.Close()

	buffer := bufio.NewReader(file)
	var values = make([]int, 0, 1024)
	for line, isPrefix, err := buffer.ReadLine(); err == nil && !isPrefix; line, isPrefix, err = buffer.ReadLine() {
		sline := string(line)
		var value int
		value, err = strconv.Atoi(sline)
		if err != nil {
			break
		}
		values = append(values, value)
	}
	return values, err
}
